package com.back.controller;

import com.back.common.utils.MD5Util;
import com.back.common.utils.Result;
import com.back.dto.LoginDTO;
import com.back.dto.RefreshTokenDTO;
import com.back.dto.RegisterDTO;
import com.back.dto.EmailVerifyRegisterDTO;
import com.back.entity.User;
import com.back.service.IUserService;
import com.back.vo.LoginResultVO;
import com.back.common.utils.RedisUtil;
import com.back.common.utils.MailUtil;
import com.back.vo.MailVo;
import com.back.vo.EmailLoginVo;
import com.back.common.utils.GsonUtil;
import com.back.common.utils.JwtUtil;
import com.back.vo.JwtVo;
import com.back.entity.EmailCodeLoginResult;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.back.common.enums.DeleteFlag;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpStatus;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.Random;

/**
 * 认证控制器
 * 负责用户注册、登录、令牌刷新等认证相关功能
 */
@RestController
@RequestMapping("/api/auth")
@Api(tags = "认证接口")
@Slf4j
@Validated
public class AuthController {
    
    @Autowired
    private IUserService userService;
    
    @Autowired
    private RedisUtil redisUtil;
    
    @Autowired
    private MailUtil mailUtil;
    
    private static final String FROM_EMAIL = "yeaonaiwohe1212@163.com";
    
    /**
     * 用户注册
     */
    @ApiOperation(value = "用户注册")
    @PostMapping("/register")
    public Result register(@Valid @RequestBody RegisterDTO registerDTO) {
        log.info("接收到注册请求: {}", registerDTO.getUsername());
        
        // 检查用户名是否已存在
        boolean userNameExists = userService.lambdaQuery()
                .eq(User::getUsername, registerDTO.getUsername())
                .count() > 0;
        if (userNameExists) {
            return Result.error().message("用户名已存在");
        }
        
        // 检查邮箱是否已存在
        boolean emailExists = userService.lambdaQuery()
                .eq(User::getEmail, registerDTO.getEmail())
                .count() > 0;
        if (emailExists) {
            return Result.error().message("邮箱已存在");
        }
        
        // 创建用户
        long currentTime = System.currentTimeMillis();
        User reigsterUser = User.builder()
                .username(registerDTO.getUsername())
                .email(registerDTO.getEmail())
                .password(MD5Util.encrypt(registerDTO.getPassword())) // 密码加密
                .role(registerDTO.getRole())
                .status(true)
                .createTime(currentTime)
                .updateTime(currentTime)
                .deleted(false)
                .build();
        
        boolean success = userService.save(reigsterUser);
        return success ? Result.ok().message("注册成功") : Result.error().message("注册失败");
    }
    
    /**
     * 发送邮箱验证码（注册用）
     */
    @ApiOperation(value = "发送邮箱验证码（注册用）")
    @GetMapping("/send-register-code")
    public Result sendRegisterCode(@RequestParam String email) {
        log.info("接收到发送注册验证码请求: {}", email);
        
        // 验证邮箱格式
        if (StringUtils.isEmpty(email) || !email.matches("^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(\\.[a-zA-Z0-9_-]+)+$")) {
            return Result.error().message("邮箱格式错误");
        }
        
        // 检查邮箱是否已注册
        boolean emailExists = userService.lambdaQuery()
                .eq(User::getEmail, email)
                .count() > 0;
        if (emailExists) {
            return Result.error().message("该邮箱已注册");
        }
        
        // 生成6位随机验证码
        Random random = new Random();
        String code = String.format("%06d", random.nextInt(1000000));
        
        // 构建邮件内容
        MailVo mailVo = new MailVo();
        mailVo.setFrom(FROM_EMAIL);
        mailVo.setTo(new String[]{email});
        mailVo.setCc(new String[]{});
        mailVo.setBcc(new String[]{});
        mailVo.setSubject("职为你 注册验证码");
        mailVo.setText("您的注册验证码是：" + code + "，有效期5分钟，请勿泄露给他人。");
        
        // 发送邮件
        try {
            mailUtil.sendMail(mailVo);
        } catch (Exception e) {
            log.error("发送注册验证码邮件失败: {}", e.getMessage());
            return Result.error().message("验证码发送失败");
        }
        
        // 将验证码存入Redis，设置5分钟有效期，使用特殊前缀区分注册验证码
        redisUtil.set("register_code:" + email, code, 60 * 5);
        
        log.info("向邮箱 {} 发送注册验证码: {}", email, code);
        return Result.ok().message("验证码发送成功");
    }
    
    /**
     * 发送邮箱验证码（登录用）
     */
    @ApiOperation(value = "发送邮箱验证码（登录用）")
    @GetMapping("/send-login-code")
    public Result sendLoginCode(@RequestParam String email) {
        log.info("接收到发送登录验证码请求: {}", email);
        
        // 验证邮箱格式
        if (StringUtils.isEmpty(email) || !email.matches("^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(\\.[a-zA-Z0-9_-]+)+$")) {
            return Result.error().message("邮箱格式错误");
        }
        
        // 检查邮箱是否已注册，未注册的邮箱不能使用验证码登录
        boolean emailExists = userService.lambdaQuery()
                .eq(User::getEmail, email)
                .count() > 0;
        if (!emailExists) {
            return Result.error().message("该邮箱未注册，请先注册");
        }
        
        // 生成6位随机验证码
        Random random = new Random();
        String code = String.format("%06d", random.nextInt(1000000));
        
        // 构建邮件内容
        MailVo mailVo = new MailVo();
        mailVo.setFrom(FROM_EMAIL);
        mailVo.setTo(new String[]{email});
        mailVo.setCc(new String[]{});
        mailVo.setBcc(new String[]{});
        mailVo.setSubject("职为你 登录验证码");
        mailVo.setText("您的登录验证码是：" + code + "，有效期5分钟，请勿泄露给他人。");
        
        // 发送邮件
        try {
            mailUtil.sendMail(mailVo);
        } catch (Exception e) {
            log.error("发送登录验证码邮件失败: {}", e.getMessage());
            return Result.error().message("验证码发送失败");
        }
        
        // 将验证码存入Redis，设置5分钟有效期
        redisUtil.set(email, code, 60 * 5);
        
        log.info("向邮箱 {} 发送登录验证码: {}", email, code);
        return Result.ok().message("验证码发送成功");
    }
    
    /**
     * 邮箱验证码注册
     */
    @ApiOperation(value = "邮箱验证码注册")
    @PostMapping("/register-with-code")
    public Result registerWithCode(@Valid @RequestBody EmailVerifyRegisterDTO registerDTO) {
        log.info("接收到邮箱验证码注册请求: {}", registerDTO.getEmail());
        
        // 获取Redis中存储的验证码
        String redisKey = "register_code:" + registerDTO.getEmail();
        String savedCode = redisUtil.get(redisKey);
        
        // 验证码不存在或不匹配
        if (StringUtils.isEmpty(savedCode) || !savedCode.equals(registerDTO.getCode())) {
            return Result.error().message("验证码错误或已过期");
        }
        
        // 检查用户名是否已存在
        boolean userNameExists = userService.lambdaQuery()
                .eq(User::getUsername, registerDTO.getUsername())
                .count() > 0;
        if (userNameExists) {
            return Result.error().message("用户名已存在");
        }
        
        // 检查邮箱是否已存在
        boolean emailExists = userService.lambdaQuery()
                .eq(User::getEmail, registerDTO.getEmail())
                .count() > 0;
        if (emailExists) {
            return Result.error().message("邮箱已存在");
        }
        
        // 创建用户
        long currentTime = System.currentTimeMillis();
        User registerUser = User.builder()
                .username(registerDTO.getUsername())
                .email(registerDTO.getEmail())
                .password(MD5Util.encrypt(registerDTO.getPassword())) // 密码加密
                .role(registerDTO.getRole())
                .status(true)
                .createTime(currentTime)
                .updateTime(currentTime)
                .deleted(false)
                .build();
        
        boolean success = userService.save(registerUser);
        
        // 注册成功后删除Redis中的验证码
        if (success) {
            redisUtil.del(redisKey);
        }
        
        return success ? Result.ok().message("注册成功") : Result.error().message("注册失败");
    }
    
    /**
     * 用户登录
     */
    @ApiOperation(value = "用户登录")
    @PostMapping("/login")
    public Result login(@Valid @RequestBody LoginDTO loginDTO, 
                        HttpServletRequest request, 
                        HttpServletResponse response) {
        log.info("接收到登录请求: {}", loginDTO.getUsername());
        try {
            LoginResultVO resultVO = userService.login(loginDTO, request);
            
            // 将token添加到响应头中
            if (resultVO != null && resultVO.getToken() != null) {
                response.setHeader("token", resultVO.getToken());
                log.info("登录成功，设置token到响应头: {}", resultVO.getToken());
            }
            
            return Result.ok()
                    .message("登录成功")
                    .data("token", resultVO.getToken())
                    .data("user", resultVO.getUser());
        } catch (Exception e) {
            log.error("登录失败: {}", e.getMessage(), e);
            return Result.error().message("登录失败: " + e.getMessage());
        }
    }
    
    /**
     * 邮箱验证码登录
     */
    @ApiOperation(value = "邮箱验证码登录")
    @PostMapping("/email-login")
    public Result emailLogin(@Valid @RequestBody EmailLoginVo emailLoginVo) {
        log.info("接收到邮箱验证码登录请求: {}", emailLoginVo.getEmail());
        
        // 获取Redis中存放的验证码
        String redisCode = redisUtil.get(emailLoginVo.getEmail());
        
        // 验证码不存在或不匹配
        if (StringUtils.isEmpty(redisCode) || !redisCode.equals(emailLoginVo.getCode())) {
            return Result.error().message("验证码错误或已过期").code(HttpStatus.SC_UNAUTHORIZED);
        }
        
        // 查询用户信息
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("email", emailLoginVo.getEmail());
        User user = userService.getOne(queryWrapper);
        
        // 用户不存在或已删除
        if (user == null || user.getDeleted()) {
            return Result.error().message("用户不存在").code(HttpStatus.SC_UNAUTHORIZED);
        }
        
        // 用户被禁用
        if (!user.getStatus()) {
            return Result.error().message("账号已被禁用").code(HttpStatus.SC_UNAUTHORIZED);
        }
        
        // 生成JWT令牌
        String token = generateToken(user);
        
        // 登录成功后删除Redis中的验证码，防止重复使用
        redisUtil.del(emailLoginVo.getEmail());
        
        Map<String, Object> data = new HashMap<>();
        data.put("token", token);
        data.put("userName", user.getUsername());
        data.put("user", user);
        
        return Result.ok().message("登录成功").data(data);
    }
    
    /**
     * 生成JWT令牌
     */
    private String generateToken(User user) {
        // 获取需要保存在JWT中的数据
        JwtVo jwtVo = new JwtVo();
        jwtVo.setId(user.getId());
        jwtVo.setName(user.getUsername());
        jwtVo.setEmail(user.getEmail());
        jwtVo.setTime(new Date().getTime());
        jwtVo.setRole(user.getRole());
        
        // 生成JWT令牌，设置过期时间为30分钟
        String jwt = JwtUtil.getJwtToken(jwtVo, 1000L * 60 * 30);
        
        // 检查重复登录情况
        String existingToken = redisUtil.get(String.valueOf(user.getId()));
        Long currentTime = new Date().getTime();
        
        if (StringUtils.isNotEmpty(existingToken)) {
            // 获取Redis中存储的JWT数据
            JwtVo redisJwt = GsonUtil.fromJson(String.valueOf(JwtUtil.getTokenBody(existingToken).get("data")), JwtVo.class);
            
            // 如果Redis中的JWT时间戳大于当前时间戳，说明有更新的登录，拒绝当前登录
            if (redisJwt.getTime() > currentTime) {
                return null;
            }
        }
        
        // 将JWT存入Redis，设置30分钟过期时间
        redisUtil.set(String.valueOf(user.getId()), jwt, 60 * 30);
        return jwt;
    }
    
    /**
     * 刷新令牌
     */
    @ApiOperation(value = "刷新令牌")
    @PostMapping("/refresh-token")
    public Result refreshToken(@Valid @RequestBody RefreshTokenDTO dto) {
        try {
            LoginResultVO resultVO = userService.refreshToken(dto.getRefreshToken());
            return Result.ok().message("令牌刷新成功").data("loginResult", resultVO);
        } catch (Exception e) {
            log.error("刷新令牌失败: {}", e.getMessage());
            return Result.error().message(e.getMessage());
        }
    }
    
    /**
     * 用户登出
     */
    @ApiOperation(value = "用户登出")
    @PostMapping("/logout")
    public Result logout(HttpServletRequest request) {
        // 从Token获取用户ID
        String token = request.getHeader("token");
        if (token == null || token.isEmpty()) {
            return Result.error().message("令牌不存在");
        }
        
        // 这里需要解析token获取用户ID，根据项目的令牌管理方式可能有所不同
        // 简化处理：从请求参数获取用户ID
        String userId = request.getParameter("userId");
        if (userId == null || userId.isEmpty()) {
            return Result.error().message("用户ID不能为空");
        }
        
        boolean success = userService.logout(Long.parseLong(userId));
        return success ? Result.ok().message("登出成功") : Result.error().message("登出失败");
    }
} 